Gas Data

The gas data represents information about various gas stations, including their location, services offered, population of compromised individuals (POC), and other relevant details. Here’s an explanation of the columns in the dataset:

  • X: Row identifier.
  • site_row_id: Identifier for the site.
  • STATE: State where the gas station is located.
  • county: County where the gas station is located.
  • ADDRESS: Street address of the gas station.
  • CITY: City where the gas station is located.
  • ycoord: Latitude coordinate of the gas station.
  • xcoord: Longitude coordinate of the gas station.
  • SITE_DESCRIPTION: Description of the gas station site.
  • service_or_fuel: Indicates whether the station provides service, fuel, or both.
  • diesel: Indicates if diesel fuel is available at the station.
  • twentyfour_hour_flag: Indicates if the station operates 24 hours.
  • car_wash: Indicates if the station has a car wash service.
  • truckstop_flag: Indicates if the station is a truck stop.
  • description: Additional description of the gas station.
  • PUMP_TECH: Pump technology used at the gas station.
  • POC: Population of compromised individuals.
  • HIFCA: High Intensity Financial Crime Area.
  • ZIPnew: ZIP code of the gas station.
  • POCAGE: Age distribution of the population of compromised individuals.
  • POCGAP: Age gap distribution of the population of compromised individuals.
  • ZIPPOC: ZIP code of the population of compromised individuals.
  • HFG: Human Factors Geometry.
  • MSA: Metropolitan Statistical Area.
  • dist.to.poc: Distance to the population of compromised individuals.
  • cate.poc.density: Categorized population of compromised individuals density.
  • cate.poc.age: Categorized population of compromised individuals age.
  • cate.poc.age.20: Categorized population of compromised individuals age group 20.
  • cate.poc.intensity: Categorized population of compromised individuals intensity.
  • cate.poc.intensity.tot: Total categorized population of compromised individuals intensity.
  • MSA_POC: Metropolitan Statistical Area population of compromised individuals.
  • MSA_POC.1: Another column indicating Metropolitan Statistical Area population of compromised individuals.

This dataset contains detailed information about gas stations and the population they serve, including geographical coordinates, services offered, and demographic characteristics of the surrounding population.

gas <- read.csv("https://ecoleman451.github.io/website/Data%20Visualization/Datasets/POC.csv")

Simple Leaflet Map

In the map below, each point represents the precise location of a gas station, with latitude and longitude coordinates derived from the “xcoord” and “ycoord” columns in the gas dataset, respectively. Hovering over each point reveals essential details such as the state, county, address, and ZIP code associated with that particular gas station. Explore the interactive map to visualize the distribution of gas stations across different regions:

 gas_samp <- gas %>% sample_n(500)

# Create a leaflet map
gas_map <- leaflet(data = gas_samp) %>%
  addTiles() %>%
  addMarkers(
    lng = ~xcoord,
    lat = ~ycoord,
    popup = ~paste("State: ", STATE, "<br>",
                   "County: ", county, "<br>",
                   "Address: ", ADDRESS, "<br>",
                   "Zip Code: ", ZIPnew)
  )
# Display the map
gas_map

Leaflet Map

Below, we enhance the leaflet map by specifying the radius and color of the markers. Each marker now appears as a circle with a fixed radius of 5 and a color set to blue. Similar to the previous map, each circle represents a gas station, and hovering over a point reveals essential information such as the state, county, address, and ZIP code associated with that specific gas station. Explore the interactive map to visualize the distribution of gas stations with this enhanced visual representation.

# Create a leaflet map
gas_map2 <- leaflet(data = gas_samp) %>%
  addTiles() %>%
  setView(lng = mean(gas_samp$xcoord), 
          lat = mean(gas_samp$ycoord), 
          zoom = 13) %>%
  addProviderTiles("Esri.WorldGrayCanvas") %>%
  addCircleMarkers(
    ~xcoord, 
    ~ycoord,
    color = "blue",  # Adjust color as needed
    radius = 5,  # Adjust radius as needed
    stroke = FALSE, 
    fillOpacity = 0.4,
    label = ~paste("State: ", STATE,
                   "County: ", county,
                   "Address: ", ADDRESS,
                   "Zip Code: ", ZIPnew)
  ) %>%
  addLegend(position = "bottomright", 
            colors = "blue",  # Adjust color as needed
            labels = "Gas Station",
            title = "Gas Stations",
            opacity = 0.4)

# Display the map
gas_map2

Best Map

In this iteration, we introduce a more sophisticated leaflet map. The radius of each point on the map is determined by the number of Points of Compromise (POCs) in the gas station’s ZIP code. Therefore, larger circles represent ZIP codes with more POCs, providing a visual indicator of potential risk areas.

Additionally, the color of each point corresponds to the type of services offered by the gas station: “Fuel”, “Service Only”, or “Both”. However, since the dataset does not include any gas stations that offer “Service Only”, only the categories “Fuel” and “Both” will be displayed on the map.

As with the previous maps, hovering over a point reveals detailed information such as the state, county, address, and ZIP code associated with the respective gas station. Explore the map to gain insights into the distribution of gas stations and their associated services.

# Create a color palette based on service_or_fuel values
service_palette <- colorFactor(palette = "Set1", domain = gas_samp$service_or_fuel)

# Create the leaflet map
gas_map3 <- leaflet(data = gas_samp) %>%
  addTiles() %>%
  addProviderTiles("Esri.WorldGrayCanvas") %>%
  addCircleMarkers(
    ~xcoord, 
    ~ycoord,
    color = ~service_palette(service_or_fuel),  # Use colorFactor
    radius = gas_samp$ZIPPOC * 10,  # Adjust radius as needed
    stroke = FALSE, 
    fillOpacity = 0.4,
    label = ~paste("State: ", STATE, "<br>",
                   "County: ", county, "<br>",
                   "Address: ", ADDRESS, "<br>",
                   "Zip Code: ", ZIPnew)
  ) %>%
  addLegend(position = "bottomright", 
            colors = service_palette(unique(gas_samp$service_or_fuel)),  # Use unique service_or_fuel values
            labels = unique(gas_samp$service_or_fuel),
            title = "Gas Stations",
            opacity = 0.4)

# Display the map
gas_map3

Philly Crime Data

The Philadelphia crime dataset contains information on various incidents, including details such as demographic characteristics, incident severity, location, and other relevant attributes. Here’s an explanation of the dataset columns:

  • dc_key: A unique identifier for each incident.
  • race: Specifies the racial background of the individuals involved, categorized as Black (Non-Hispanic), Hispanic (Black or White), and so on.
  • sex: Indicates the gender of the individuals involved, classified as Male or Female.
  • fatal: Indicates whether the incident resulted in a fatality (Fatal) or not (Nonfatal).
  • date: Records the date and time when the incident occurred.
  • has_court_case: Specifies whether the incident is associated with a court case (Yes/No).
  • age: Represents the age of the individuals involved in the incident.
  • street_name: Denotes the name of the street where the incident took place.
  • block_number: Indicates the block number related to the incident’s location.
  • zip_code: Provides the ZIP code of the incident location.
  • council_district: Identifies the council district corresponding to the incident location.
  • police_district: Identifies the police district corresponding to the incident location.
  • neighborhood: Specifies the neighborhood where the incident occurred.
  • house_district: Identifies the house district associated with the incident location.
  • senate_district: Identifies the senate district associated with the incident location.
  • school_catchment: Specifies the school catchment area associated with the incident location.
  • lng: Represents the longitude coordinate of the incident location.
  • lat: Represents the latitude coordinate of the incident location.

This dataset provides valuable insights into the demographics of individuals involved in various incidents, the nature and severity of the incidents, and their spatial distribution across different neighborhoods and districts within Philadelphia. Analyzing this data can help identify patterns, trends, and areas of concern related to crime and public safety in the city. We’re narrowing down our dataset to focus solely on the data from 2023. Since there’s no specific variable denoting the year, we’ll derive it from the existing ‘date’ variable. After creating the ‘Year’ variable, we can then filter the data to include only observations from 2023. Consequently, our updated dataset now comprises 1666 observations and 19 variables, including the newly added ‘Year’.

philly <- read.csv("https://ecoleman451.github.io/website/Data%20Visualization/Datasets/PhillyCrimeSince2015.csv")

# Convert date variable to date format
philly$date <- as.Date(philly$date, format = "%m/%d/%Y %H:%M")

# Extract year from date variable
philly$year <- format(philly$date, "%Y")

philly <- subset(philly, year=="2023")

Leaflet Map

Now, let’s visualize fatal versus non-fatal crimes that occurred in Philadelphia in the year 2023 on a leaflet map. We’ll once again utilize the “color” function to differentiate between the two types of crimes. Each category, “Fatal” or “Nonfatal,” will be assigned a distinct color, providing a visual representation of the crime type. The map follows a similar format to the ones above, with each circle point denoting a specific crime incident. Hovering over a point will reveal details such as the “Neighborhood,” “Date,” “Race,” “Sex,” “Age,” and “Street” associated with that particular crime. Upon visual inspection of the map, it appears that there is a notable disparity between the number of non-fatal crimes and fatal crimes. However, to confirm this observation, further analysis would be necessary.

library(leaflet)
library(dplyr)
# Create color palette for fatal and non-fatal crimes
fatal <- "red"
non_fatal <- "blue"

# Create leaflet map
map <- leaflet(philly) %>%
  addTiles() %>%
  addCircleMarkers(
    ~lng, ~lat,
    color = ifelse(philly$fatal == "Fatal", fatal, non_fatal),
    radius = 5,
    label = ~paste("Neighborhood: ", neighborhood,
                   "Date: ", date,
                   "Race: ", race,
                   "Sex: ", sex,
                   "Age: ", age,
                   "Street: ", street_name),
    labelOptions = labelOptions(
      direction = "auto"
    )
  ) %>%
  addLegend(
    position = "bottomright",
    colors = c(fatal, non_fatal),
    labels = c("Fatal", "Non-Fatal"),
    title = "Crime Type"
  ) %>%
  addScaleBar() %>%
  addControl(
    html = "<h4>Philadelphia Crime Locations (2015-2024)</h4>",
    position = "topright"
  )

# Display the map
map

Better Leaflet Map

Now, let’s create an enhanced leaflet map to visualize fatal versus non-fatal crimes that occurred in Philadelphia. We’ll utilize the “color” function once again, with colors representing whether a crime was labeled as “Fatal” or “Nonfatal”. Each category will be uniquely colored, offering clear visual identification of the crime type. We’ll represent each crime location with a circle marker on the map. Hovering over a point will display detailed information including “Object ID”, “Year”, “Race”, “Sex”, “Age”, “Wound”, and “Location” for each crime incident.

# Load required libraries
library(leaflet)
library(sf)

# Suppress messages while reading GeoJSON files
options(warn=-1)

# Read the data without printing messages
philly <- st_read("https://pengdsci.github.io/STA553VIZ/w08/PhillyShootings.geojson", quiet = TRUE)
phillyNeighbor <- st_read("https://pengdsci.github.io/STA553VIZ/w08/Neighborhoods_Philadelphia.geojson", quiet = TRUE)

# Reset warning settings
options(warn=0)

# Convert 'philly' data to sf object
philly_sf <- st_as_sf(philly, coords = c("point_x", "point_y"), crs = 4326)

# Define color palette for fatal and non-fatal crimes
fatal_color <- "red"
non_fatal_color <- "gold"

# Create leaflet map
map <- leaflet() %>%
  addProviderTiles(providers$Esri.WorldGrayCanvas) %>%
  addPolygons(data = phillyNeighbor,
              color = 'skyblue',
              weight = 1)  %>%
  addCircleMarkers(data = philly_sf,
                   ~point_x, ~point_y,
                   color = ifelse(philly$fatal == 1, fatal_color, non_fatal_color),
                   radius = 5,
                   popup = ~paste("Object ID: ", objectid,
                                  "<br>Year: ", year,
                                  "<br>Race: ", race,
                                  "<br>Sex: ", sex,
                                  "<br>Age: ", age,
                                  "<br>Wound: ", wound,
                                  "<br>Location: ", location),
                   labelOptions = labelOptions(
                     direction = "auto"
                   )
  ) %>%
  addLegend(
    position = "bottomright",
    colors = c("red", "gold"),
    labels = c("Fatal", "Non-Fatal"),
    title = "Crime Type"
  ) %>%
  addScaleBar() %>%
  addControl(
    html = "<h4>Philadelphia Crime Locations (2015-2024)</h4>",
    position = "topright"
  ) %>%
  addProviderTiles(providers$Esri.WorldGrayCanvas) %>%
  setView(lng = -75.1527, lat = 39.9707, zoom = 11)

# Display the map
map



U.S. Presidential Election Data (2000-2024)

Our initial dataset, named “election”, encompasses Presidential election outcomes spanning the years 2000, 2004, 2008, 2012, 2016, and 2020. With 72,617 observations and 12 variables, it provides comprehensive insights into each state’s and county’s election results, detailing the winning candidate in each county, along with the total votes received by each candidate.

Prior to analysis, some data cleaning was imperative, particularly concerning the county FIPS codes—a unique 5-digit identifier assigned to every county in the United States. Initially, certain codes erroneously contained only 4 digits, notably when a “0” preceded the first digit. For instance, Autauga County, Alabama’s FIPS code “01001” was recorded as “1001” in the dataset. This discrepancy was rectified using the “TEXT” function in Excel, applied before importing the data into the “election” set.

Utilizing the “election” dataset, our objective is to split the data into county-level and state-level subsets. Both subsets include a new variable named “party_percentage,” calculated to ascertain the percentage of voters favoring the winning party within their respective state or county. The “county_data” subset provides election results categorized by county, while the “state_data” subset presents election outcomes aggregated by state. Furthermore, both subsets retain solely the winning party’s information for analysis.

# Load the required library
library(dplyr)

# Read the data
election <- read.csv("https://ecoleman451.github.io/website/Data%20Visualization/Datasets/PresidentialElection2000To2020.csv")

# County-level Data
county_data <- election %>%
  group_by(year, state, county_name) %>%
  mutate(party_percentage = candidatevotes / sum(candidatevotes) * 100) %>%
  filter(party_percentage == max(party_percentage)) %>%
  select(year, state, county_fips, party, candidate, candidatevotes, party_percentage)

# State-level Data
state_data <- election %>%
  group_by(year, state) %>%
  mutate(party_percentage = candidatevotes / sum(candidatevotes) * 100) %>%
  filter(party_percentage == max(party_percentage)) %>%
  select(year, state, party, candidate, candidatevotes, party_percentage)

# Save county-level data to a new CSV file
write.csv(county_data, file = "county_level_data.csv", row.names = FALSE)

# Save state-level data to a new CSV file
write.csv(state_data, file = "state_level_data.csv", row.names = FALSE)

Choropleth Map

Now that we’ve split the dataset into “county_data,” focusing solely on election results (specifically the winning party) at the county level, we can leverage Tableau, an interactive data visualization tool, to craft a Choropleth Map. This map will display presidential election outcomes at the county level. Different colors are assigned to represent the major political parties (Democrat & Republican), and each county’s shading reflects the winning political party in a specific election year. The interactive map includes a filter to alter the displayed year(s). Additionally, hover text appears when hovering over a specific county on the map, providing information such as “year,” “state,” “party,” “candidatevotes,” and “party_percentage” for the respective county.


LS0tDQp0aXRsZTogIk1hcHBpbmciDQphdXRob3I6ICJFZHdhcmQgQ29sZW1hbiINCmRhdGU6ICJXZXN0IENoZXN0ZXIgVW5pdmVyc2l0eSINCm91dHB1dDoNCiAgaHRtbF9kb2N1bWVudDogDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZGVwdGg6IDQNCiAgICB0b2NfZmxvYXQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHllcw0KICAgIHRoZW1lOiByZWFkYWJsZQ0KICAgIGVkaXRvcl9vcHRpb25zOg0KICAgICAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQ0KLS0tDQoNCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+DQovKiBDb21tb24gc3R5bGVzICovDQpkaXYjVE9DIGxpIHsNCiAgICBsaXN0LXN0eWxlOm5vbmU7DQogICAgYmFja2dyb3VuZC1jb2xvcjpsaWdodGdyYXk7DQogICAgYmFja2dyb3VuZC1pbWFnZTpub25lOw0KICAgIGJhY2tncm91bmQtcmVwZWF0Om5vbmU7DQogICAgYmFja2dyb3VuZC1wb3NpdGlvbjowOw0KICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KICAgIGNvbG9yOiAjNzgwYzBjOw0KfQ0KDQpoMS50aXRsZSB7DQogICAgZm9udC1zaXplOiAyNHB4Ow0KICAgIGNvbG9yOiBEYXJrUmVkOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCiAgICBmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsNCiAgICBmb250LXZhcmlhbnQtY2Fwczogbm9ybWFsOw0KfQ0KaDQuYXV0aG9yIHsgDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBEYXJrUmVkOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmg0LmRhdGUgeyANCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IERhcmtCbHVlOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgxIHsgDQogICAgZm9udC1zaXplOiAyMnB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIGZvbnQtd2VpZ2h0OiBib2xkOw0KICAgIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCmgyIHsgDQogICAgZm9udC1zaXplOiAxOHB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBuYXZ5Ow0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQpoMyB7IA0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogbmF2eTsNCiAgICBmb250LXdlaWdodDogYm9sZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KaDQgeyANCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KLyogVGFiIGZlYXR1cmVzICovDQoubmF2PmxpPmEgew0KICAgIHBvc2l0aW9uOiByZWxhdGl2ZTsNCiAgICBkaXNwbGF5OiBibG9jazsNCiAgICBwYWRkaW5nOiAycHggMTVweDsNCiAgICBjb2xvcjogIzk5MDAwMDsNCn0NCi5uYXYtcGlsbHM+bGkuYWN0aXZlPmEsIC5uYXYtcGlsbHM+bGkuYWN0aXZlPmE6aG92ZXIsIC5uYXYtcGlsbHM+bGkuYWN0aXZlPmE6Zm9jdXMgew0KICAgIGNvbG9yOiAjZmZmZmZmOw0KICAgIGJhY2tncm91bmQtY29sb3I6ICM5OTAwMDA7DQp9DQovKg0KbmF2LXBpbGxzPmxpOm50aC1jaGlsZCgyKSB7DQogICAgYmFja2dyb3VuZDogZ3JlZW47DQogfQ0KICovDQppbWcgew0KICAgIGJvcmRlcjogMXB4IHNvbGlkICM1NTU7DQp9DQoNCi8qIFJlbW92ZSBib3JkZXIgZnJvbSBsZWFmbGV0IG1hcmtlciBpbWFnZXMgKi8NCi5sZWFmbGV0LXBhbmUgaW1nLmxlYWZsZXQtbWFya2VyLWljb24gew0KICAgIGJvcmRlcjogbm9uZSAhaW1wb3J0YW50Ow0KfQ0KPC9zdHlsZT4NCg0KDQpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRSwgY29tbWVudD1OQX0NCm9wdGlvbnMocmVwb3MgPSBsaXN0KENSQU49Imh0dHA6Ly9jcmFuLnJzdHVkaW8uY29tLyIpKQ0KaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCiAgIGxpYnJhcnkodGlkeXZlcnNlKQ0KfQ0KaWYgKCFyZXF1aXJlKCJrbml0ciIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJrbml0ciIpDQogICBsaWJyYXJ5KGtuaXRyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJjb3dwbG90IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImNvd3Bsb3QiKQ0KICAgbGlicmFyeShjb3dwbG90KQ0KfQ0KaWYgKCFyZXF1aXJlKCJsYXRleDJleHAiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygibGF0ZXgyZXhwIikNCiAgIGxpYnJhcnkobGF0ZXgyZXhwKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwbG90bHkiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygicGxvdGx5IikNCiAgIGxpYnJhcnkocGxvdGx5KQ0KfQ0KaWYgKCFyZXF1aXJlKCJnYXBtaW5kZXIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygiZ2FwbWluZGVyIikNCiAgIGxpYnJhcnkoZ2FwbWluZGVyKQ0KfQ0KaWYgKCFyZXF1aXJlKCJwbmciKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoInBuZyIpICAgIA0KICAgIGxpYnJhcnkoInBuZyIpDQp9DQppZiAoIXJlcXVpcmUoIlJDdXJsIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJSQ3VybCIpICAgIA0KICAgIGxpYnJhcnkoIlJDdXJsIikNCn0NCmlmICghcmVxdWlyZSgiY29sb3VycGlja2VyIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJjb2xvdXJwaWNrZXIiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiY29sb3VycGlja2VyIikNCn0NCmlmICghcmVxdWlyZSgiZ2dhbmltYXRlIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnZ2FuaW1hdGUiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ2dhbmltYXRlIikNCn0NCmlmICghcmVxdWlyZSgiZ2lmc2tpIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnaWZza2kiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ2lmc2tpIikNCn0NCmlmICghcmVxdWlyZSgibWFnaWNrIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJtYWdpY2siKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibWFnaWNrIikNCn0NCmlmICghcmVxdWlyZSgiZ3JEZXZpY2VzIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnckRldmljZXMiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ3JEZXZpY2VzIikNCn0NCmlmICghcmVxdWlyZSgianBlZyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygianBlZyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJqcGVnIikNCn0NCmlmICghcmVxdWlyZSgiZ2dyaWRnZXMiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdncmlkZ2VzIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImdncmlkZ2VzIikNCn0NCmlmICghcmVxdWlyZSgicGx5ciIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygicGx5ciIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJwbHlyIikNCn0NCmlmICghcmVxdWlyZSgiZ2dpcmFwaCIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiZ2dpcmFwaCIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnZ2lyYXBoIikNCn0NCmlmICghcmVxdWlyZSgiaGlnaGNoYXJ0ZXIiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImhpZ2hjaGFydGVyIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImhpZ2hjaGFydGVyIikNCn0NCmlmICghcmVxdWlyZSgiZm9yZWNhc3QiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImZvcmVjYXN0IikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImZvcmVjYXN0IikNCn0NCmlmICghcmVxdWlyZSgibGVhZmxldCIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygibGVhZmxldCIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJsZWFmbGV0IikNCn0NCmlmICghcmVxdWlyZSgic2YiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoInNmIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoInNmIikNCn0NCiMjIA0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFLCAgICAgICANCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsICAgDQogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gVFJVRSwgICANCiAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gRkFMU0UsDQogICAgICAgICAgICAgICAgICAgICAgY29tbWVudCA9IE5BKQ0KIyBjb2RlIGNodW5rIHNwZWNpZmllcyB3aGV0aGVyIHRoZSBSIGNvZGUsIHdhcm5pbmdzLCBhbmQgb3V0cHV0IA0KIyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXQgZmlsZXMuDQppZiAoIXJlcXVpcmUoIlN0YXQyRGF0YSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJTdGF0MkRhdGEiKQ0KICAgbGlicmFyeShTdGF0MkRhdGEpDQp9DQppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImtuaXRyIikNCiAgIGxpYnJhcnkoa25pdHIpDQp9DQoNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IFRSVUUsICAgDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQSkNCmBgYA0KDQojIEdhcyBEYXRhDQogIFRoZSBnYXMgZGF0YSByZXByZXNlbnRzIGluZm9ybWF0aW9uIGFib3V0IHZhcmlvdXMgZ2FzIHN0YXRpb25zLCBpbmNsdWRpbmcgdGhlaXIgbG9jYXRpb24sIHNlcnZpY2VzIG9mZmVyZWQsIHBvcHVsYXRpb24gb2YgY29tcHJvbWlzZWQgaW5kaXZpZHVhbHMgKFBPQyksIGFuZCBvdGhlciByZWxldmFudCBkZXRhaWxzLiBIZXJlJ3MgYW4gZXhwbGFuYXRpb24gb2YgdGhlIGNvbHVtbnMgaW4gdGhlIGRhdGFzZXQ6DQoNCjx1bD4NCiAgPGxpPlg6IFJvdyBpZGVudGlmaWVyLjwvbGk+DQogIDxsaT5zaXRlX3Jvd19pZDogSWRlbnRpZmllciBmb3IgdGhlIHNpdGUuPC9saT4NCiAgPGxpPlNUQVRFOiBTdGF0ZSB3aGVyZSB0aGUgZ2FzIHN0YXRpb24gaXMgbG9jYXRlZC48L2xpPg0KICA8bGk+Y291bnR5OiBDb3VudHkgd2hlcmUgdGhlIGdhcyBzdGF0aW9uIGlzIGxvY2F0ZWQuPC9saT4NCiAgPGxpPkFERFJFU1M6IFN0cmVldCBhZGRyZXNzIG9mIHRoZSBnYXMgc3RhdGlvbi48L2xpPg0KICA8bGk+Q0lUWTogQ2l0eSB3aGVyZSB0aGUgZ2FzIHN0YXRpb24gaXMgbG9jYXRlZC48L2xpPg0KICA8bGk+eWNvb3JkOiBMYXRpdHVkZSBjb29yZGluYXRlIG9mIHRoZSBnYXMgc3RhdGlvbi48L2xpPg0KICA8bGk+eGNvb3JkOiBMb25naXR1ZGUgY29vcmRpbmF0ZSBvZiB0aGUgZ2FzIHN0YXRpb24uPC9saT4NCiAgPGxpPlNJVEVfREVTQ1JJUFRJT046IERlc2NyaXB0aW9uIG9mIHRoZSBnYXMgc3RhdGlvbiBzaXRlLjwvbGk+DQogIDxsaT5zZXJ2aWNlX29yX2Z1ZWw6IEluZGljYXRlcyB3aGV0aGVyIHRoZSBzdGF0aW9uIHByb3ZpZGVzIHNlcnZpY2UsIGZ1ZWwsIG9yIGJvdGguPC9saT4NCiAgPGxpPmRpZXNlbDogSW5kaWNhdGVzIGlmIGRpZXNlbCBmdWVsIGlzIGF2YWlsYWJsZSBhdCB0aGUgc3RhdGlvbi48L2xpPg0KICA8bGk+dHdlbnR5Zm91cl9ob3VyX2ZsYWc6IEluZGljYXRlcyBpZiB0aGUgc3RhdGlvbiBvcGVyYXRlcyAyNCBob3Vycy48L2xpPg0KICA8bGk+Y2FyX3dhc2g6IEluZGljYXRlcyBpZiB0aGUgc3RhdGlvbiBoYXMgYSBjYXIgd2FzaCBzZXJ2aWNlLjwvbGk+DQogIDxsaT50cnVja3N0b3BfZmxhZzogSW5kaWNhdGVzIGlmIHRoZSBzdGF0aW9uIGlzIGEgdHJ1Y2sgc3RvcC48L2xpPg0KICA8bGk+ZGVzY3JpcHRpb246IEFkZGl0aW9uYWwgZGVzY3JpcHRpb24gb2YgdGhlIGdhcyBzdGF0aW9uLjwvbGk+DQogIDxsaT5QVU1QX1RFQ0g6IFB1bXAgdGVjaG5vbG9neSB1c2VkIGF0IHRoZSBnYXMgc3RhdGlvbi48L2xpPg0KICA8bGk+UE9DOiBQb3B1bGF0aW9uIG9mIGNvbXByb21pc2VkIGluZGl2aWR1YWxzLjwvbGk+DQogIDxsaT5ISUZDQTogSGlnaCBJbnRlbnNpdHkgRmluYW5jaWFsIENyaW1lIEFyZWEuPC9saT4NCiAgPGxpPlpJUG5ldzogWklQIGNvZGUgb2YgdGhlIGdhcyBzdGF0aW9uLjwvbGk+DQogIDxsaT5QT0NBR0U6IEFnZSBkaXN0cmlidXRpb24gb2YgdGhlIHBvcHVsYXRpb24gb2YgY29tcHJvbWlzZWQgaW5kaXZpZHVhbHMuPC9saT4NCiAgPGxpPlBPQ0dBUDogQWdlIGdhcCBkaXN0cmlidXRpb24gb2YgdGhlIHBvcHVsYXRpb24gb2YgY29tcHJvbWlzZWQgaW5kaXZpZHVhbHMuPC9saT4NCiAgPGxpPlpJUFBPQzogWklQIGNvZGUgb2YgdGhlIHBvcHVsYXRpb24gb2YgY29tcHJvbWlzZWQgaW5kaXZpZHVhbHMuPC9saT4NCiAgPGxpPkhGRzogSHVtYW4gRmFjdG9ycyBHZW9tZXRyeS48L2xpPg0KICA8bGk+TVNBOiBNZXRyb3BvbGl0YW4gU3RhdGlzdGljYWwgQXJlYS48L2xpPg0KICA8bGk+ZGlzdC50by5wb2M6IERpc3RhbmNlIHRvIHRoZSBwb3B1bGF0aW9uIG9mIGNvbXByb21pc2VkIGluZGl2aWR1YWxzLjwvbGk+DQogIDxsaT5jYXRlLnBvYy5kZW5zaXR5OiBDYXRlZ29yaXplZCBwb3B1bGF0aW9uIG9mIGNvbXByb21pc2VkIGluZGl2aWR1YWxzIGRlbnNpdHkuPC9saT4NCiAgPGxpPmNhdGUucG9jLmFnZTogQ2F0ZWdvcml6ZWQgcG9wdWxhdGlvbiBvZiBjb21wcm9taXNlZCBpbmRpdmlkdWFscyBhZ2UuPC9saT4NCiAgPGxpPmNhdGUucG9jLmFnZS4yMDogQ2F0ZWdvcml6ZWQgcG9wdWxhdGlvbiBvZiBjb21wcm9taXNlZCBpbmRpdmlkdWFscyBhZ2UgZ3JvdXAgMjAuPC9saT4NCiAgPGxpPmNhdGUucG9jLmludGVuc2l0eTogQ2F0ZWdvcml6ZWQgcG9wdWxhdGlvbiBvZiBjb21wcm9taXNlZCBpbmRpdmlkdWFscyBpbnRlbnNpdHkuPC9saT4NCiAgPGxpPmNhdGUucG9jLmludGVuc2l0eS50b3Q6IFRvdGFsIGNhdGVnb3JpemVkIHBvcHVsYXRpb24gb2YgY29tcHJvbWlzZWQgaW5kaXZpZHVhbHMgaW50ZW5zaXR5LjwvbGk+DQogIDxsaT5NU0FfUE9DOiBNZXRyb3BvbGl0YW4gU3RhdGlzdGljYWwgQXJlYSBwb3B1bGF0aW9uIG9mIGNvbXByb21pc2VkIGluZGl2aWR1YWxzLjwvbGk+DQogIDxsaT5NU0FfUE9DLjE6IEFub3RoZXIgY29sdW1uIGluZGljYXRpbmcgTWV0cm9wb2xpdGFuIFN0YXRpc3RpY2FsIEFyZWEgcG9wdWxhdGlvbiBvZiBjb21wcm9taXNlZCBpbmRpdmlkdWFscy48L2xpPg0KPC91bD4NCg0KVGhpcyBkYXRhc2V0IGNvbnRhaW5zIGRldGFpbGVkIGluZm9ybWF0aW9uIGFib3V0IGdhcyBzdGF0aW9ucyBhbmQgdGhlIHBvcHVsYXRpb24gdGhleSBzZXJ2ZSwgaW5jbHVkaW5nIGdlb2dyYXBoaWNhbCBjb29yZGluYXRlcywgc2VydmljZXMgb2ZmZXJlZCwgYW5kIGRlbW9ncmFwaGljIGNoYXJhY3RlcmlzdGljcyBvZiB0aGUgc3Vycm91bmRpbmcgcG9wdWxhdGlvbi4NCmBgYHtyLCBjb21tZW50PU5BfQ0KZ2FzIDwtIHJlYWQuY3N2KCJodHRwczovL2Vjb2xlbWFuNDUxLmdpdGh1Yi5pby93ZWJzaXRlL0RhdGElMjBWaXN1YWxpemF0aW9uL0RhdGFzZXRzL1BPQy5jc3YiKQ0KYGBgDQoNCiMjIFNpbXBsZSBMZWFmbGV0IE1hcA0KICBJbiB0aGUgbWFwIGJlbG93LCBlYWNoIHBvaW50IHJlcHJlc2VudHMgdGhlIHByZWNpc2UgbG9jYXRpb24gb2YgYSBnYXMgc3RhdGlvbiwgd2l0aCBsYXRpdHVkZSBhbmQgbG9uZ2l0dWRlIGNvb3JkaW5hdGVzIGRlcml2ZWQgZnJvbSB0aGUgInhjb29yZCIgYW5kICJ5Y29vcmQiIGNvbHVtbnMgaW4gdGhlIGdhcyBkYXRhc2V0LCByZXNwZWN0aXZlbHkuIEhvdmVyaW5nIG92ZXIgZWFjaCBwb2ludCByZXZlYWxzIGVzc2VudGlhbCBkZXRhaWxzIHN1Y2ggYXMgdGhlIHN0YXRlLCBjb3VudHksIGFkZHJlc3MsIGFuZCBaSVAgY29kZSBhc3NvY2lhdGVkIHdpdGggdGhhdCBwYXJ0aWN1bGFyIGdhcyBzdGF0aW9uLiBFeHBsb3JlIHRoZSBpbnRlcmFjdGl2ZSBtYXAgdG8gdmlzdWFsaXplIHRoZSBkaXN0cmlidXRpb24gb2YgZ2FzIHN0YXRpb25zIGFjcm9zcyBkaWZmZXJlbnQgcmVnaW9uczoNCmBgYHtyLCBjb21tZW50PU5BfQ0KIGdhc19zYW1wIDwtIGdhcyAlPiUgc2FtcGxlX24oNTAwKQ0KDQojIENyZWF0ZSBhIGxlYWZsZXQgbWFwDQpnYXNfbWFwIDwtIGxlYWZsZXQoZGF0YSA9IGdhc19zYW1wKSAlPiUNCiAgYWRkVGlsZXMoKSAlPiUNCiAgYWRkTWFya2VycygNCiAgICBsbmcgPSB+eGNvb3JkLA0KICAgIGxhdCA9IH55Y29vcmQsDQogICAgcG9wdXAgPSB+cGFzdGUoIlN0YXRlOiAiLCBTVEFURSwgIjxicj4iLA0KICAgICAgICAgICAgICAgICAgICJDb3VudHk6ICIsIGNvdW50eSwgIjxicj4iLA0KICAgICAgICAgICAgICAgICAgICJBZGRyZXNzOiAiLCBBRERSRVNTLCAiPGJyPiIsDQogICAgICAgICAgICAgICAgICAgIlppcCBDb2RlOiAiLCBaSVBuZXcpDQogICkNCiMgRGlzcGxheSB0aGUgbWFwDQpnYXNfbWFwDQpgYGANCg0KIyMgTGVhZmxldCBNYXANCiAgQmVsb3csIHdlIGVuaGFuY2UgdGhlIGxlYWZsZXQgbWFwIGJ5IHNwZWNpZnlpbmcgdGhlIHJhZGl1cyBhbmQgY29sb3Igb2YgdGhlIG1hcmtlcnMuIEVhY2ggbWFya2VyIG5vdyBhcHBlYXJzIGFzIGEgY2lyY2xlIHdpdGggYSBmaXhlZCByYWRpdXMgb2YgNSBhbmQgYSBjb2xvciBzZXQgdG8gYmx1ZS4gU2ltaWxhciB0byB0aGUgcHJldmlvdXMgbWFwLCBlYWNoIGNpcmNsZSByZXByZXNlbnRzIGEgZ2FzIHN0YXRpb24sIGFuZCBob3ZlcmluZyBvdmVyIGEgcG9pbnQgcmV2ZWFscyBlc3NlbnRpYWwgaW5mb3JtYXRpb24gc3VjaCBhcyB0aGUgc3RhdGUsIGNvdW50eSwgYWRkcmVzcywgYW5kIFpJUCBjb2RlIGFzc29jaWF0ZWQgd2l0aCB0aGF0IHNwZWNpZmljIGdhcyBzdGF0aW9uLiBFeHBsb3JlIHRoZSBpbnRlcmFjdGl2ZSBtYXAgdG8gdmlzdWFsaXplIHRoZSBkaXN0cmlidXRpb24gb2YgZ2FzIHN0YXRpb25zIHdpdGggdGhpcyBlbmhhbmNlZCB2aXN1YWwgcmVwcmVzZW50YXRpb24uDQpgYGB7ciwgY29tbWVudD1OQX0NCiMgQ3JlYXRlIGEgbGVhZmxldCBtYXANCmdhc19tYXAyIDwtIGxlYWZsZXQoZGF0YSA9IGdhc19zYW1wKSAlPiUNCiAgYWRkVGlsZXMoKSAlPiUNCiAgc2V0VmlldyhsbmcgPSBtZWFuKGdhc19zYW1wJHhjb29yZCksIA0KICAgICAgICAgIGxhdCA9IG1lYW4oZ2FzX3NhbXAkeWNvb3JkKSwgDQogICAgICAgICAgem9vbSA9IDEzKSAlPiUNCiAgYWRkUHJvdmlkZXJUaWxlcygiRXNyaS5Xb3JsZEdyYXlDYW52YXMiKSAlPiUNCiAgYWRkQ2lyY2xlTWFya2VycygNCiAgICB+eGNvb3JkLCANCiAgICB+eWNvb3JkLA0KICAgIGNvbG9yID0gImJsdWUiLCAgIyBBZGp1c3QgY29sb3IgYXMgbmVlZGVkDQogICAgcmFkaXVzID0gNSwgICMgQWRqdXN0IHJhZGl1cyBhcyBuZWVkZWQNCiAgICBzdHJva2UgPSBGQUxTRSwgDQogICAgZmlsbE9wYWNpdHkgPSAwLjQsDQogICAgbGFiZWwgPSB+cGFzdGUoIlN0YXRlOiAiLCBTVEFURSwNCiAgICAgICAgICAgICAgICAgICAiQ291bnR5OiAiLCBjb3VudHksDQogICAgICAgICAgICAgICAgICAgIkFkZHJlc3M6ICIsIEFERFJFU1MsDQogICAgICAgICAgICAgICAgICAgIlppcCBDb2RlOiAiLCBaSVBuZXcpDQogICkgJT4lDQogIGFkZExlZ2VuZChwb3NpdGlvbiA9ICJib3R0b21yaWdodCIsIA0KICAgICAgICAgICAgY29sb3JzID0gImJsdWUiLCAgIyBBZGp1c3QgY29sb3IgYXMgbmVlZGVkDQogICAgICAgICAgICBsYWJlbHMgPSAiR2FzIFN0YXRpb24iLA0KICAgICAgICAgICAgdGl0bGUgPSAiR2FzIFN0YXRpb25zIiwNCiAgICAgICAgICAgIG9wYWNpdHkgPSAwLjQpDQoNCiMgRGlzcGxheSB0aGUgbWFwDQpnYXNfbWFwMg0KYGBgDQoNCiMjIEJlc3QgTWFwDQpJbiB0aGlzIGl0ZXJhdGlvbiwgd2UgaW50cm9kdWNlIGEgbW9yZSBzb3BoaXN0aWNhdGVkIGxlYWZsZXQgbWFwLiBUaGUgcmFkaXVzIG9mIGVhY2ggcG9pbnQgb24gdGhlIG1hcCBpcyBkZXRlcm1pbmVkIGJ5IHRoZSBudW1iZXIgb2YgUG9pbnRzIG9mIENvbXByb21pc2UgKFBPQ3MpIGluIHRoZSBnYXMgc3RhdGlvbidzIFpJUCBjb2RlLiBUaGVyZWZvcmUsIGxhcmdlciBjaXJjbGVzIHJlcHJlc2VudCBaSVAgY29kZXMgd2l0aCBtb3JlIFBPQ3MsIHByb3ZpZGluZyBhIHZpc3VhbCBpbmRpY2F0b3Igb2YgcG90ZW50aWFsIHJpc2sgYXJlYXMuDQoNCkFkZGl0aW9uYWxseSwgdGhlIGNvbG9yIG9mIGVhY2ggcG9pbnQgY29ycmVzcG9uZHMgdG8gdGhlIHR5cGUgb2Ygc2VydmljZXMgb2ZmZXJlZCBieSB0aGUgZ2FzIHN0YXRpb246ICJGdWVsIiwgIlNlcnZpY2UgT25seSIsIG9yICJCb3RoIi4gSG93ZXZlciwgc2luY2UgdGhlIGRhdGFzZXQgZG9lcyBub3QgaW5jbHVkZSBhbnkgZ2FzIHN0YXRpb25zIHRoYXQgb2ZmZXIgIlNlcnZpY2UgT25seSIsIG9ubHkgdGhlIGNhdGVnb3JpZXMgIkZ1ZWwiIGFuZCAiQm90aCIgd2lsbCBiZSBkaXNwbGF5ZWQgb24gdGhlIG1hcC4NCg0KQXMgd2l0aCB0aGUgcHJldmlvdXMgbWFwcywgaG92ZXJpbmcgb3ZlciBhIHBvaW50IHJldmVhbHMgZGV0YWlsZWQgaW5mb3JtYXRpb24gc3VjaCBhcyB0aGUgc3RhdGUsIGNvdW50eSwgYWRkcmVzcywgYW5kIFpJUCBjb2RlIGFzc29jaWF0ZWQgd2l0aCB0aGUgcmVzcGVjdGl2ZSBnYXMgc3RhdGlvbi4gRXhwbG9yZSB0aGUgbWFwIHRvIGdhaW4gaW5zaWdodHMgaW50byB0aGUgZGlzdHJpYnV0aW9uIG9mIGdhcyBzdGF0aW9ucyBhbmQgdGhlaXIgYXNzb2NpYXRlZCBzZXJ2aWNlcy4NCmBgYHtyLCBjb21tZW50PU5BfQ0KIyBDcmVhdGUgYSBjb2xvciBwYWxldHRlIGJhc2VkIG9uIHNlcnZpY2Vfb3JfZnVlbCB2YWx1ZXMNCnNlcnZpY2VfcGFsZXR0ZSA8LSBjb2xvckZhY3RvcihwYWxldHRlID0gIlNldDEiLCBkb21haW4gPSBnYXNfc2FtcCRzZXJ2aWNlX29yX2Z1ZWwpDQoNCiMgQ3JlYXRlIHRoZSBsZWFmbGV0IG1hcA0KZ2FzX21hcDMgPC0gbGVhZmxldChkYXRhID0gZ2FzX3NhbXApICU+JQ0KICBhZGRUaWxlcygpICU+JQ0KICBhZGRQcm92aWRlclRpbGVzKCJFc3JpLldvcmxkR3JheUNhbnZhcyIpICU+JQ0KICBhZGRDaXJjbGVNYXJrZXJzKA0KICAgIH54Y29vcmQsIA0KICAgIH55Y29vcmQsDQogICAgY29sb3IgPSB+c2VydmljZV9wYWxldHRlKHNlcnZpY2Vfb3JfZnVlbCksICAjIFVzZSBjb2xvckZhY3Rvcg0KICAgIHJhZGl1cyA9IGdhc19zYW1wJFpJUFBPQyAqIDEwLCAgIyBBZGp1c3QgcmFkaXVzIGFzIG5lZWRlZA0KICAgIHN0cm9rZSA9IEZBTFNFLCANCiAgICBmaWxsT3BhY2l0eSA9IDAuNCwNCiAgICBsYWJlbCA9IH5wYXN0ZSgiU3RhdGU6ICIsIFNUQVRFLCAiPGJyPiIsDQogICAgICAgICAgICAgICAgICAgIkNvdW50eTogIiwgY291bnR5LCAiPGJyPiIsDQogICAgICAgICAgICAgICAgICAgIkFkZHJlc3M6ICIsIEFERFJFU1MsICI8YnI+IiwNCiAgICAgICAgICAgICAgICAgICAiWmlwIENvZGU6ICIsIFpJUG5ldykNCiAgKSAlPiUNCiAgYWRkTGVnZW5kKHBvc2l0aW9uID0gImJvdHRvbXJpZ2h0IiwgDQogICAgICAgICAgICBjb2xvcnMgPSBzZXJ2aWNlX3BhbGV0dGUodW5pcXVlKGdhc19zYW1wJHNlcnZpY2Vfb3JfZnVlbCkpLCAgIyBVc2UgdW5pcXVlIHNlcnZpY2Vfb3JfZnVlbCB2YWx1ZXMNCiAgICAgICAgICAgIGxhYmVscyA9IHVuaXF1ZShnYXNfc2FtcCRzZXJ2aWNlX29yX2Z1ZWwpLA0KICAgICAgICAgICAgdGl0bGUgPSAiR2FzIFN0YXRpb25zIiwNCiAgICAgICAgICAgIG9wYWNpdHkgPSAwLjQpDQoNCiMgRGlzcGxheSB0aGUgbWFwDQpnYXNfbWFwMw0KYGBgDQoNCg0KIyBQaGlsbHkgQ3JpbWUgRGF0YQ0KVGhlIFBoaWxhZGVscGhpYSBjcmltZSBkYXRhc2V0IGNvbnRhaW5zIGluZm9ybWF0aW9uIG9uIHZhcmlvdXMgaW5jaWRlbnRzLCBpbmNsdWRpbmcgZGV0YWlscyBzdWNoIGFzIGRlbW9ncmFwaGljIGNoYXJhY3RlcmlzdGljcywgaW5jaWRlbnQgc2V2ZXJpdHksIGxvY2F0aW9uLCBhbmQgb3RoZXIgcmVsZXZhbnQgYXR0cmlidXRlcy4gSGVyZSdzIGFuIGV4cGxhbmF0aW9uIG9mIHRoZSBkYXRhc2V0IGNvbHVtbnM6DQoNCjx1bD4NCiAgPGxpPmRjX2tleTogQSB1bmlxdWUgaWRlbnRpZmllciBmb3IgZWFjaCBpbmNpZGVudC48L2xpPg0KICA8bGk+cmFjZTogU3BlY2lmaWVzIHRoZSByYWNpYWwgYmFja2dyb3VuZCBvZiB0aGUgaW5kaXZpZHVhbHMgaW52b2x2ZWQsIGNhdGVnb3JpemVkIGFzIEJsYWNrIChOb24tSGlzcGFuaWMpLCBIaXNwYW5pYyAoQmxhY2sgb3IgV2hpdGUpLCBhbmQgc28gb24uPC9saT4NCiAgPGxpPnNleDogSW5kaWNhdGVzIHRoZSBnZW5kZXIgb2YgdGhlIGluZGl2aWR1YWxzIGludm9sdmVkLCBjbGFzc2lmaWVkIGFzIE1hbGUgb3IgRmVtYWxlLjwvbGk+DQogIDxsaT5mYXRhbDogSW5kaWNhdGVzIHdoZXRoZXIgdGhlIGluY2lkZW50IHJlc3VsdGVkIGluIGEgZmF0YWxpdHkgKEZhdGFsKSBvciBub3QgKE5vbmZhdGFsKS48L2xpPg0KICA8bGk+ZGF0ZTogUmVjb3JkcyB0aGUgZGF0ZSBhbmQgdGltZSB3aGVuIHRoZSBpbmNpZGVudCBvY2N1cnJlZC48L2xpPg0KICA8bGk+aGFzX2NvdXJ0X2Nhc2U6IFNwZWNpZmllcyB3aGV0aGVyIHRoZSBpbmNpZGVudCBpcyBhc3NvY2lhdGVkIHdpdGggYSBjb3VydCBjYXNlIChZZXMvTm8pLjwvbGk+DQogIDxsaT5hZ2U6IFJlcHJlc2VudHMgdGhlIGFnZSBvZiB0aGUgaW5kaXZpZHVhbHMgaW52b2x2ZWQgaW4gdGhlIGluY2lkZW50LjwvbGk+DQogIDxsaT5zdHJlZXRfbmFtZTogRGVub3RlcyB0aGUgbmFtZSBvZiB0aGUgc3RyZWV0IHdoZXJlIHRoZSBpbmNpZGVudCB0b29rIHBsYWNlLjwvbGk+DQogIDxsaT5ibG9ja19udW1iZXI6IEluZGljYXRlcyB0aGUgYmxvY2sgbnVtYmVyIHJlbGF0ZWQgdG8gdGhlIGluY2lkZW50J3MgbG9jYXRpb24uPC9saT4NCiAgPGxpPnppcF9jb2RlOiBQcm92aWRlcyB0aGUgWklQIGNvZGUgb2YgdGhlIGluY2lkZW50IGxvY2F0aW9uLjwvbGk+DQogIDxsaT5jb3VuY2lsX2Rpc3RyaWN0OiBJZGVudGlmaWVzIHRoZSBjb3VuY2lsIGRpc3RyaWN0IGNvcnJlc3BvbmRpbmcgdG8gdGhlIGluY2lkZW50IGxvY2F0aW9uLjwvbGk+DQogIDxsaT5wb2xpY2VfZGlzdHJpY3Q6IElkZW50aWZpZXMgdGhlIHBvbGljZSBkaXN0cmljdCBjb3JyZXNwb25kaW5nIHRvIHRoZSBpbmNpZGVudCBsb2NhdGlvbi48L2xpPg0KICA8bGk+bmVpZ2hib3Job29kOiBTcGVjaWZpZXMgdGhlIG5laWdoYm9yaG9vZCB3aGVyZSB0aGUgaW5jaWRlbnQgb2NjdXJyZWQuPC9saT4NCiAgPGxpPmhvdXNlX2Rpc3RyaWN0OiBJZGVudGlmaWVzIHRoZSBob3VzZSBkaXN0cmljdCBhc3NvY2lhdGVkIHdpdGggdGhlIGluY2lkZW50IGxvY2F0aW9uLjwvbGk+DQogIDxsaT5zZW5hdGVfZGlzdHJpY3Q6IElkZW50aWZpZXMgdGhlIHNlbmF0ZSBkaXN0cmljdCBhc3NvY2lhdGVkIHdpdGggdGhlIGluY2lkZW50IGxvY2F0aW9uLjwvbGk+DQogIDxsaT5zY2hvb2xfY2F0Y2htZW50OiBTcGVjaWZpZXMgdGhlIHNjaG9vbCBjYXRjaG1lbnQgYXJlYSBhc3NvY2lhdGVkIHdpdGggdGhlIGluY2lkZW50IGxvY2F0aW9uLjwvbGk+DQogIDxsaT5sbmc6IFJlcHJlc2VudHMgdGhlIGxvbmdpdHVkZSBjb29yZGluYXRlIG9mIHRoZSBpbmNpZGVudCBsb2NhdGlvbi48L2xpPg0KICA8bGk+bGF0OiBSZXByZXNlbnRzIHRoZSBsYXRpdHVkZSBjb29yZGluYXRlIG9mIHRoZSBpbmNpZGVudCBsb2NhdGlvbi48L2xpPg0KPC91bD4NCg0KVGhpcyBkYXRhc2V0IHByb3ZpZGVzIHZhbHVhYmxlIGluc2lnaHRzIGludG8gdGhlIGRlbW9ncmFwaGljcyBvZiBpbmRpdmlkdWFscyBpbnZvbHZlZCBpbiB2YXJpb3VzIGluY2lkZW50cywgdGhlIG5hdHVyZSBhbmQgc2V2ZXJpdHkgb2YgdGhlIGluY2lkZW50cywgYW5kIHRoZWlyIHNwYXRpYWwgZGlzdHJpYnV0aW9uIGFjcm9zcyBkaWZmZXJlbnQgbmVpZ2hib3Job29kcyBhbmQgZGlzdHJpY3RzIHdpdGhpbiBQaGlsYWRlbHBoaWEuIEFuYWx5emluZyB0aGlzIGRhdGEgY2FuIGhlbHAgaWRlbnRpZnkgcGF0dGVybnMsIHRyZW5kcywgYW5kIGFyZWFzIG9mIGNvbmNlcm4gcmVsYXRlZCB0byBjcmltZSBhbmQgcHVibGljIHNhZmV0eSBpbiB0aGUgY2l0eS4NCldlJ3JlIG5hcnJvd2luZyBkb3duIG91ciBkYXRhc2V0IHRvIGZvY3VzIHNvbGVseSBvbiB0aGUgZGF0YSBmcm9tIDIwMjMuIFNpbmNlIHRoZXJlJ3Mgbm8gc3BlY2lmaWMgdmFyaWFibGUgZGVub3RpbmcgdGhlIHllYXIsIHdlJ2xsIGRlcml2ZSBpdCBmcm9tIHRoZSBleGlzdGluZyAnZGF0ZScgdmFyaWFibGUuIEFmdGVyIGNyZWF0aW5nIHRoZSAnWWVhcicgdmFyaWFibGUsIHdlIGNhbiB0aGVuIGZpbHRlciB0aGUgZGF0YSB0byBpbmNsdWRlIG9ubHkgb2JzZXJ2YXRpb25zIGZyb20gMjAyMy4gQ29uc2VxdWVudGx5LCBvdXIgdXBkYXRlZCBkYXRhc2V0IG5vdyBjb21wcmlzZXMgMTY2NiBvYnNlcnZhdGlvbnMgYW5kIDE5IHZhcmlhYmxlcywgaW5jbHVkaW5nIHRoZSBuZXdseSBhZGRlZCAnWWVhcicuDQpgYGB7ciwgY29tbWVudD1OQX0NCnBoaWxseSA8LSByZWFkLmNzdigiaHR0cHM6Ly9lY29sZW1hbjQ1MS5naXRodWIuaW8vd2Vic2l0ZS9EYXRhJTIwVmlzdWFsaXphdGlvbi9EYXRhc2V0cy9QaGlsbHlDcmltZVNpbmNlMjAxNS5jc3YiKQ0KDQojIENvbnZlcnQgZGF0ZSB2YXJpYWJsZSB0byBkYXRlIGZvcm1hdA0KcGhpbGx5JGRhdGUgPC0gYXMuRGF0ZShwaGlsbHkkZGF0ZSwgZm9ybWF0ID0gIiVtLyVkLyVZICVIOiVNIikNCg0KIyBFeHRyYWN0IHllYXIgZnJvbSBkYXRlIHZhcmlhYmxlDQpwaGlsbHkkeWVhciA8LSBmb3JtYXQocGhpbGx5JGRhdGUsICIlWSIpDQoNCnBoaWxseSA8LSBzdWJzZXQocGhpbGx5LCB5ZWFyPT0iMjAyMyIpDQpgYGANCg0KIyMgTGVhZmxldCBNYXANCiAgTm93LCBsZXQncyB2aXN1YWxpemUgZmF0YWwgdmVyc3VzIG5vbi1mYXRhbCBjcmltZXMgdGhhdCBvY2N1cnJlZCBpbiBQaGlsYWRlbHBoaWEgaW4gdGhlIHllYXIgMjAyMyBvbiBhIGxlYWZsZXQgbWFwLiBXZSdsbCBvbmNlIGFnYWluIHV0aWxpemUgdGhlICJjb2xvciIgZnVuY3Rpb24gdG8gZGlmZmVyZW50aWF0ZSBiZXR3ZWVuIHRoZSB0d28gdHlwZXMgb2YgY3JpbWVzLiBFYWNoIGNhdGVnb3J5LCAiRmF0YWwiIG9yICJOb25mYXRhbCwiIHdpbGwgYmUgYXNzaWduZWQgYSBkaXN0aW5jdCBjb2xvciwgcHJvdmlkaW5nIGEgdmlzdWFsIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjcmltZSB0eXBlLiBUaGUgbWFwIGZvbGxvd3MgYSBzaW1pbGFyIGZvcm1hdCB0byB0aGUgb25lcyBhYm92ZSwgd2l0aCBlYWNoIGNpcmNsZSBwb2ludCBkZW5vdGluZyBhIHNwZWNpZmljIGNyaW1lIGluY2lkZW50LiBIb3ZlcmluZyBvdmVyIGEgcG9pbnQgd2lsbCByZXZlYWwgZGV0YWlscyBzdWNoIGFzIHRoZSAiTmVpZ2hib3Job29kLCIgIkRhdGUsIiAiUmFjZSwiICJTZXgsIiAiQWdlLCIgYW5kICJTdHJlZXQiIGFzc29jaWF0ZWQgd2l0aCB0aGF0IHBhcnRpY3VsYXIgY3JpbWUuIFVwb24gdmlzdWFsIGluc3BlY3Rpb24gb2YgdGhlIG1hcCwgaXQgYXBwZWFycyB0aGF0IHRoZXJlIGlzIGEgbm90YWJsZSBkaXNwYXJpdHkgYmV0d2VlbiB0aGUgbnVtYmVyIG9mIG5vbi1mYXRhbCBjcmltZXMgYW5kIGZhdGFsIGNyaW1lcy4gSG93ZXZlciwgdG8gY29uZmlybSB0aGlzIG9ic2VydmF0aW9uLCBmdXJ0aGVyIGFuYWx5c2lzIHdvdWxkIGJlIG5lY2Vzc2FyeS4NCmBgYHtyLCBjb21tZW50PU5BfQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShkcGx5cikNCiMgQ3JlYXRlIGNvbG9yIHBhbGV0dGUgZm9yIGZhdGFsIGFuZCBub24tZmF0YWwgY3JpbWVzDQpmYXRhbCA8LSAicmVkIg0Kbm9uX2ZhdGFsIDwtICJibHVlIg0KDQojIENyZWF0ZSBsZWFmbGV0IG1hcA0KbWFwIDwtIGxlYWZsZXQocGhpbGx5KSAlPiUNCiAgYWRkVGlsZXMoKSAlPiUNCiAgYWRkQ2lyY2xlTWFya2VycygNCiAgICB+bG5nLCB+bGF0LA0KICAgIGNvbG9yID0gaWZlbHNlKHBoaWxseSRmYXRhbCA9PSAiRmF0YWwiLCBmYXRhbCwgbm9uX2ZhdGFsKSwNCiAgICByYWRpdXMgPSA1LA0KICAgIGxhYmVsID0gfnBhc3RlKCJOZWlnaGJvcmhvb2Q6ICIsIG5laWdoYm9yaG9vZCwNCiAgICAgICAgICAgICAgICAgICAiRGF0ZTogIiwgZGF0ZSwNCiAgICAgICAgICAgICAgICAgICAiUmFjZTogIiwgcmFjZSwNCiAgICAgICAgICAgICAgICAgICAiU2V4OiAiLCBzZXgsDQogICAgICAgICAgICAgICAgICAgIkFnZTogIiwgYWdlLA0KICAgICAgICAgICAgICAgICAgICJTdHJlZXQ6ICIsIHN0cmVldF9uYW1lKSwNCiAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMoDQogICAgICBkaXJlY3Rpb24gPSAiYXV0byINCiAgICApDQogICkgJT4lDQogIGFkZExlZ2VuZCgNCiAgICBwb3NpdGlvbiA9ICJib3R0b21yaWdodCIsDQogICAgY29sb3JzID0gYyhmYXRhbCwgbm9uX2ZhdGFsKSwNCiAgICBsYWJlbHMgPSBjKCJGYXRhbCIsICJOb24tRmF0YWwiKSwNCiAgICB0aXRsZSA9ICJDcmltZSBUeXBlIg0KICApICU+JQ0KICBhZGRTY2FsZUJhcigpICU+JQ0KICBhZGRDb250cm9sKA0KICAgIGh0bWwgPSAiPGg0PlBoaWxhZGVscGhpYSBDcmltZSBMb2NhdGlvbnMgKDIwMTUtMjAyNCk8L2g0PiIsDQogICAgcG9zaXRpb24gPSAidG9wcmlnaHQiDQogICkNCg0KIyBEaXNwbGF5IHRoZSBtYXANCm1hcA0KYGBgDQoNCiMjIEJldHRlciBMZWFmbGV0IE1hcA0KICBOb3csIGxldCdzIGNyZWF0ZSBhbiBlbmhhbmNlZCBsZWFmbGV0IG1hcCB0byB2aXN1YWxpemUgZmF0YWwgdmVyc3VzIG5vbi1mYXRhbCBjcmltZXMgdGhhdCBvY2N1cnJlZCBpbiBQaGlsYWRlbHBoaWEuIFdlJ2xsIHV0aWxpemUgdGhlICJjb2xvciIgZnVuY3Rpb24gb25jZSBhZ2Fpbiwgd2l0aCBjb2xvcnMgcmVwcmVzZW50aW5nIHdoZXRoZXIgYSBjcmltZSB3YXMgbGFiZWxlZCBhcyAiRmF0YWwiIG9yICJOb25mYXRhbCIuIEVhY2ggY2F0ZWdvcnkgd2lsbCBiZSB1bmlxdWVseSBjb2xvcmVkLCBvZmZlcmluZyBjbGVhciB2aXN1YWwgaWRlbnRpZmljYXRpb24gb2YgdGhlIGNyaW1lIHR5cGUuIFdlJ2xsIHJlcHJlc2VudCBlYWNoIGNyaW1lIGxvY2F0aW9uIHdpdGggYSBjaXJjbGUgbWFya2VyIG9uIHRoZSBtYXAuIEhvdmVyaW5nIG92ZXIgYSBwb2ludCB3aWxsIGRpc3BsYXkgZGV0YWlsZWQgaW5mb3JtYXRpb24gaW5jbHVkaW5nICJPYmplY3QgSUQiLCAiWWVhciIsICJSYWNlIiwgIlNleCIsICJBZ2UiLCAiV291bmQiLCBhbmQgIkxvY2F0aW9uIiBmb3IgZWFjaCBjcmltZSBpbmNpZGVudC4NCmBgYHtyfQ0KIyBMb2FkIHJlcXVpcmVkIGxpYnJhcmllcw0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShzZikNCg0KIyBTdXBwcmVzcyBtZXNzYWdlcyB3aGlsZSByZWFkaW5nIEdlb0pTT04gZmlsZXMNCm9wdGlvbnMod2Fybj0tMSkNCg0KIyBSZWFkIHRoZSBkYXRhIHdpdGhvdXQgcHJpbnRpbmcgbWVzc2FnZXMNCnBoaWxseSA8LSBzdF9yZWFkKCJodHRwczovL3Blbmdkc2NpLmdpdGh1Yi5pby9TVEE1NTNWSVovdzA4L1BoaWxseVNob290aW5ncy5nZW9qc29uIiwgcXVpZXQgPSBUUlVFKQ0KcGhpbGx5TmVpZ2hib3IgPC0gc3RfcmVhZCgiaHR0cHM6Ly9wZW5nZHNjaS5naXRodWIuaW8vU1RBNTUzVklaL3cwOC9OZWlnaGJvcmhvb2RzX1BoaWxhZGVscGhpYS5nZW9qc29uIiwgcXVpZXQgPSBUUlVFKQ0KDQojIFJlc2V0IHdhcm5pbmcgc2V0dGluZ3MNCm9wdGlvbnMod2Fybj0wKQ0KDQojIENvbnZlcnQgJ3BoaWxseScgZGF0YSB0byBzZiBvYmplY3QNCnBoaWxseV9zZiA8LSBzdF9hc19zZihwaGlsbHksIGNvb3JkcyA9IGMoInBvaW50X3giLCAicG9pbnRfeSIpLCBjcnMgPSA0MzI2KQ0KDQojIERlZmluZSBjb2xvciBwYWxldHRlIGZvciBmYXRhbCBhbmQgbm9uLWZhdGFsIGNyaW1lcw0KZmF0YWxfY29sb3IgPC0gInJlZCINCm5vbl9mYXRhbF9jb2xvciA8LSAiZ29sZCINCg0KIyBDcmVhdGUgbGVhZmxldCBtYXANCm1hcCA8LSBsZWFmbGV0KCkgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJEVzcmkuV29ybGRHcmF5Q2FudmFzKSAlPiUNCiAgYWRkUG9seWdvbnMoZGF0YSA9IHBoaWxseU5laWdoYm9yLA0KICAgICAgICAgICAgICBjb2xvciA9ICdza3libHVlJywNCiAgICAgICAgICAgICAgd2VpZ2h0ID0gMSkgICU+JQ0KICBhZGRDaXJjbGVNYXJrZXJzKGRhdGEgPSBwaGlsbHlfc2YsDQogICAgICAgICAgICAgICAgICAgfnBvaW50X3gsIH5wb2ludF95LA0KICAgICAgICAgICAgICAgICAgIGNvbG9yID0gaWZlbHNlKHBoaWxseSRmYXRhbCA9PSAxLCBmYXRhbF9jb2xvciwgbm9uX2ZhdGFsX2NvbG9yKSwNCiAgICAgICAgICAgICAgICAgICByYWRpdXMgPSA1LA0KICAgICAgICAgICAgICAgICAgIHBvcHVwID0gfnBhc3RlKCJPYmplY3QgSUQ6ICIsIG9iamVjdGlkLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+WWVhcjogIiwgeWVhciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPlJhY2U6ICIsIHJhY2UsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj5TZXg6ICIsIHNleCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPkFnZTogIiwgYWdlLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+V291bmQ6ICIsIHdvdW5kLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+TG9jYXRpb246ICIsIGxvY2F0aW9uKSwNCiAgICAgICAgICAgICAgICAgICBsYWJlbE9wdGlvbnMgPSBsYWJlbE9wdGlvbnMoDQogICAgICAgICAgICAgICAgICAgICBkaXJlY3Rpb24gPSAiYXV0byINCiAgICAgICAgICAgICAgICAgICApDQogICkgJT4lDQogIGFkZExlZ2VuZCgNCiAgICBwb3NpdGlvbiA9ICJib3R0b21yaWdodCIsDQogICAgY29sb3JzID0gYygicmVkIiwgImdvbGQiKSwNCiAgICBsYWJlbHMgPSBjKCJGYXRhbCIsICJOb24tRmF0YWwiKSwNCiAgICB0aXRsZSA9ICJDcmltZSBUeXBlIg0KICApICU+JQ0KICBhZGRTY2FsZUJhcigpICU+JQ0KICBhZGRDb250cm9sKA0KICAgIGh0bWwgPSAiPGg0PlBoaWxhZGVscGhpYSBDcmltZSBMb2NhdGlvbnMgKDIwMTUtMjAyNCk8L2g0PiIsDQogICAgcG9zaXRpb24gPSAidG9wcmlnaHQiDQogICkgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJEVzcmkuV29ybGRHcmF5Q2FudmFzKSAlPiUNCiAgc2V0VmlldyhsbmcgPSAtNzUuMTUyNywgbGF0ID0gMzkuOTcwNywgem9vbSA9IDExKQ0KDQojIERpc3BsYXkgdGhlIG1hcA0KbWFwDQpgYGANCg0KXA0KDQpcDQoNCiMgVS5TLiBQcmVzaWRlbnRpYWwgRWxlY3Rpb24gRGF0YSAoMjAwMC0yMDI0KQ0KT3VyIGluaXRpYWwgZGF0YXNldCwgbmFtZWQgImVsZWN0aW9uIiwgZW5jb21wYXNzZXMgUHJlc2lkZW50aWFsIGVsZWN0aW9uIG91dGNvbWVzIHNwYW5uaW5nIHRoZSB5ZWFycyAyMDAwLCAyMDA0LCAyMDA4LCAyMDEyLCAyMDE2LCBhbmQgMjAyMC4gV2l0aCA3Miw2MTcgb2JzZXJ2YXRpb25zIGFuZCAxMiB2YXJpYWJsZXMsIGl0IHByb3ZpZGVzIGNvbXByZWhlbnNpdmUgaW5zaWdodHMgaW50byBlYWNoIHN0YXRlJ3MgYW5kIGNvdW50eSdzIGVsZWN0aW9uIHJlc3VsdHMsIGRldGFpbGluZyB0aGUgd2lubmluZyBjYW5kaWRhdGUgaW4gZWFjaCBjb3VudHksIGFsb25nIHdpdGggdGhlIHRvdGFsIHZvdGVzIHJlY2VpdmVkIGJ5IGVhY2ggY2FuZGlkYXRlLg0KDQpQcmlvciB0byBhbmFseXNpcywgc29tZSBkYXRhIGNsZWFuaW5nIHdhcyBpbXBlcmF0aXZlLCBwYXJ0aWN1bGFybHkgY29uY2VybmluZyB0aGUgY291bnR5IEZJUFMgY29kZXPigJRhIHVuaXF1ZSA1LWRpZ2l0IGlkZW50aWZpZXIgYXNzaWduZWQgdG8gZXZlcnkgY291bnR5IGluIHRoZSBVbml0ZWQgU3RhdGVzLiBJbml0aWFsbHksIGNlcnRhaW4gY29kZXMgZXJyb25lb3VzbHkgY29udGFpbmVkIG9ubHkgNCBkaWdpdHMsIG5vdGFibHkgd2hlbiBhICIwIiBwcmVjZWRlZCB0aGUgZmlyc3QgZGlnaXQuIEZvciBpbnN0YW5jZSwgQXV0YXVnYSBDb3VudHksIEFsYWJhbWEncyBGSVBTIGNvZGUgIjAxMDAxIiB3YXMgcmVjb3JkZWQgYXMgIjEwMDEiIGluIHRoZSBkYXRhc2V0LiBUaGlzIGRpc2NyZXBhbmN5IHdhcyByZWN0aWZpZWQgdXNpbmcgdGhlICJURVhUIiBmdW5jdGlvbiBpbiBFeGNlbCwgYXBwbGllZCBiZWZvcmUgaW1wb3J0aW5nIHRoZSBkYXRhIGludG8gdGhlICJlbGVjdGlvbiIgc2V0Lg0KDQpVdGlsaXppbmcgdGhlICJlbGVjdGlvbiIgZGF0YXNldCwgb3VyIG9iamVjdGl2ZSBpcyB0byBzcGxpdCB0aGUgZGF0YSBpbnRvIGNvdW50eS1sZXZlbCBhbmQgc3RhdGUtbGV2ZWwgc3Vic2V0cy4gQm90aCBzdWJzZXRzIGluY2x1ZGUgYSBuZXcgdmFyaWFibGUgbmFtZWQgInBhcnR5X3BlcmNlbnRhZ2UsIiBjYWxjdWxhdGVkIHRvIGFzY2VydGFpbiB0aGUgcGVyY2VudGFnZSBvZiB2b3RlcnMgZmF2b3JpbmcgdGhlIHdpbm5pbmcgcGFydHkgd2l0aGluIHRoZWlyIHJlc3BlY3RpdmUgc3RhdGUgb3IgY291bnR5LiBUaGUgImNvdW50eV9kYXRhIiBzdWJzZXQgcHJvdmlkZXMgZWxlY3Rpb24gcmVzdWx0cyBjYXRlZ29yaXplZCBieSBjb3VudHksIHdoaWxlIHRoZSAic3RhdGVfZGF0YSIgc3Vic2V0IHByZXNlbnRzIGVsZWN0aW9uIG91dGNvbWVzIGFnZ3JlZ2F0ZWQgYnkgc3RhdGUuIEZ1cnRoZXJtb3JlLCBib3RoIHN1YnNldHMgcmV0YWluIHNvbGVseSB0aGUgd2lubmluZyBwYXJ0eSdzIGluZm9ybWF0aW9uIGZvciBhbmFseXNpcy4NCmBgYHtyfQ0KIyBMb2FkIHRoZSByZXF1aXJlZCBsaWJyYXJ5DQpsaWJyYXJ5KGRwbHlyKQ0KDQojIFJlYWQgdGhlIGRhdGENCmVsZWN0aW9uIDwtIHJlYWQuY3N2KCJodHRwczovL2Vjb2xlbWFuNDUxLmdpdGh1Yi5pby93ZWJzaXRlL0RhdGElMjBWaXN1YWxpemF0aW9uL0RhdGFzZXRzL1ByZXNpZGVudGlhbEVsZWN0aW9uMjAwMFRvMjAyMC5jc3YiKQ0KDQojIENvdW50eS1sZXZlbCBEYXRhDQpjb3VudHlfZGF0YSA8LSBlbGVjdGlvbiAlPiUNCiAgZ3JvdXBfYnkoeWVhciwgc3RhdGUsIGNvdW50eV9uYW1lKSAlPiUNCiAgbXV0YXRlKHBhcnR5X3BlcmNlbnRhZ2UgPSBjYW5kaWRhdGV2b3RlcyAvIHN1bShjYW5kaWRhdGV2b3RlcykgKiAxMDApICU+JQ0KICBmaWx0ZXIocGFydHlfcGVyY2VudGFnZSA9PSBtYXgocGFydHlfcGVyY2VudGFnZSkpICU+JQ0KICBzZWxlY3QoeWVhciwgc3RhdGUsIGNvdW50eV9maXBzLCBwYXJ0eSwgY2FuZGlkYXRlLCBjYW5kaWRhdGV2b3RlcywgcGFydHlfcGVyY2VudGFnZSkNCg0KIyBTdGF0ZS1sZXZlbCBEYXRhDQpzdGF0ZV9kYXRhIDwtIGVsZWN0aW9uICU+JQ0KICBncm91cF9ieSh5ZWFyLCBzdGF0ZSkgJT4lDQogIG11dGF0ZShwYXJ0eV9wZXJjZW50YWdlID0gY2FuZGlkYXRldm90ZXMgLyBzdW0oY2FuZGlkYXRldm90ZXMpICogMTAwKSAlPiUNCiAgZmlsdGVyKHBhcnR5X3BlcmNlbnRhZ2UgPT0gbWF4KHBhcnR5X3BlcmNlbnRhZ2UpKSAlPiUNCiAgc2VsZWN0KHllYXIsIHN0YXRlLCBwYXJ0eSwgY2FuZGlkYXRlLCBjYW5kaWRhdGV2b3RlcywgcGFydHlfcGVyY2VudGFnZSkNCg0KIyBTYXZlIGNvdW50eS1sZXZlbCBkYXRhIHRvIGEgbmV3IENTViBmaWxlDQp3cml0ZS5jc3YoY291bnR5X2RhdGEsIGZpbGUgPSAiY291bnR5X2xldmVsX2RhdGEuY3N2Iiwgcm93Lm5hbWVzID0gRkFMU0UpDQoNCiMgU2F2ZSBzdGF0ZS1sZXZlbCBkYXRhIHRvIGEgbmV3IENTViBmaWxlDQp3cml0ZS5jc3Yoc3RhdGVfZGF0YSwgZmlsZSA9ICJzdGF0ZV9sZXZlbF9kYXRhLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KYGBgDQoNCiMjIENob3JvcGxldGggTWFwDQogIE5vdyB0aGF0IHdlJ3ZlIHNwbGl0IHRoZSBkYXRhc2V0IGludG8gImNvdW50eV9kYXRhLCIgZm9jdXNpbmcgc29sZWx5IG9uIGVsZWN0aW9uIHJlc3VsdHMgKHNwZWNpZmljYWxseSB0aGUgd2lubmluZyBwYXJ0eSkgYXQgdGhlIGNvdW50eSBsZXZlbCwgd2UgY2FuIGxldmVyYWdlIFRhYmxlYXUsIGFuIGludGVyYWN0aXZlIGRhdGEgdmlzdWFsaXphdGlvbiB0b29sLCB0byBjcmFmdCBhIENob3JvcGxldGggTWFwLiBUaGlzIG1hcCB3aWxsIGRpc3BsYXkgcHJlc2lkZW50aWFsIGVsZWN0aW9uIG91dGNvbWVzIGF0IHRoZSBjb3VudHkgbGV2ZWwuIERpZmZlcmVudCBjb2xvcnMgYXJlIGFzc2lnbmVkIHRvIHJlcHJlc2VudCB0aGUgbWFqb3IgcG9saXRpY2FsIHBhcnRpZXMgKERlbW9jcmF0ICYgUmVwdWJsaWNhbiksIGFuZCBlYWNoIGNvdW50eSdzIHNoYWRpbmcgcmVmbGVjdHMgdGhlIHdpbm5pbmcgcG9saXRpY2FsIHBhcnR5IGluIGEgc3BlY2lmaWMgZWxlY3Rpb24geWVhci4gVGhlIGludGVyYWN0aXZlIG1hcCBpbmNsdWRlcyBhIGZpbHRlciB0byBhbHRlciB0aGUgZGlzcGxheWVkIHllYXIocykuIEFkZGl0aW9uYWxseSwgaG92ZXIgdGV4dCBhcHBlYXJzIHdoZW4gaG92ZXJpbmcgb3ZlciBhIHNwZWNpZmljIGNvdW50eSBvbiB0aGUgbWFwLCBwcm92aWRpbmcgaW5mb3JtYXRpb24gc3VjaCBhcyAieWVhciwiICJzdGF0ZSwiICJwYXJ0eSwiICJjYW5kaWRhdGV2b3RlcywiIGFuZCAicGFydHlfcGVyY2VudGFnZSIgZm9yIHRoZSByZXNwZWN0aXZlIGNvdW50eS4NClwNCjx0YWJsZSBib3JkZXIgPSAwIGJvcmRlcmNvbG9yPSJkYXJrZ3JlZW4iIGJnY29sb3I9JyNmNmY2ZjYnICB3aWR0aD0xMDAlICBhbGlnbiA9IGNlbnRlcj4NCjx0cj4NCjx0ZD4NCjxkaXYgY2xhc3M9J3RhYmxlYXVQbGFjZWhvbGRlcicgaWQ9J3ZpejE3MTIyNjkyOTQwMjAnIHN0eWxlPSdwb3NpdGlvbjogcmVsYXRpdmUnPjxub3NjcmlwdD48YSBocmVmPScjJz48aW1nIGFsdD0nQ2hvcm9wbGV0aCBNYXAgJyBzcmM9J2h0dHBzOiYjNDc7JiM0NztwdWJsaWMudGFibGVhdS5jb20mIzQ3O3N0YXRpYyYjNDc7aW1hZ2VzJiM0NztDaCYjNDc7Q2hvcm9wbGV0aF9NYXBfRmluYWwmIzQ3O1NoZWV0MSYjNDc7MV9yc3MucG5nJyBzdHlsZT0nYm9yZGVyOiBub25lJyAvPjwvYT48L25vc2NyaXB0PjxvYmplY3QgY2xhc3M9J3RhYmxlYXVWaXonICBzdHlsZT0nZGlzcGxheTpub25lOyc+PHBhcmFtIG5hbWU9J2hvc3RfdXJsJyB2YWx1ZT0naHR0cHMlM0ElMkYlMkZwdWJsaWMudGFibGVhdS5jb20lMkYnIC8+IDxwYXJhbSBuYW1lPSdlbWJlZF9jb2RlX3ZlcnNpb24nIHZhbHVlPSczJyAvPiA8cGFyYW0gbmFtZT0nc2l0ZV9yb290JyB2YWx1ZT0nJyAvPjxwYXJhbSBuYW1lPSduYW1lJyB2YWx1ZT0nQ2hvcm9wbGV0aF9NYXBfRmluYWwmIzQ3O1NoZWV0MScgLz48cGFyYW0gbmFtZT0ndGFicycgdmFsdWU9J25vJyAvPjxwYXJhbSBuYW1lPSd0b29sYmFyJyB2YWx1ZT0neWVzJyAvPjxwYXJhbSBuYW1lPSdzdGF0aWNfaW1hZ2UnIHZhbHVlPSdodHRwczomIzQ3OyYjNDc7cHVibGljLnRhYmxlYXUuY29tJiM0NztzdGF0aWMmIzQ3O2ltYWdlcyYjNDc7Q2gmIzQ3O0Nob3JvcGxldGhfTWFwX0ZpbmFsJiM0NztTaGVldDEmIzQ3OzEucG5nJyAvPiA8cGFyYW0gbmFtZT0nYW5pbWF0ZV90cmFuc2l0aW9uJyB2YWx1ZT0neWVzJyAvPjxwYXJhbSBuYW1lPSdkaXNwbGF5X3N0YXRpY19pbWFnZScgdmFsdWU9J3llcycgLz48cGFyYW0gbmFtZT0nZGlzcGxheV9zcGlubmVyJyB2YWx1ZT0neWVzJyAvPjxwYXJhbSBuYW1lPSdkaXNwbGF5X292ZXJsYXknIHZhbHVlPSd5ZXMnIC8+PHBhcmFtIG5hbWU9J2Rpc3BsYXlfY291bnQnIHZhbHVlPSd5ZXMnIC8+PHBhcmFtIG5hbWU9J2xhbmd1YWdlJyB2YWx1ZT0nZW4tVVMnIC8+PHBhcmFtIG5hbWU9J2ZpbHRlcicgdmFsdWU9J3B1Ymxpc2g9eWVzJyAvPjwvb2JqZWN0PjwvZGl2PiAgICAgICAgICAgICAgICANCjxzY3JpcHQgdHlwZT0ndGV4dC9qYXZhc2NyaXB0Jz4gICAgICAgICAgICAgICAgICAgIHZhciBkaXZFbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3ZpejE3MTIyNjkyOTQwMjAnKTsgICAgICAgICAgICAgICAgICAgIHZhciB2aXpFbGVtZW50ID0gZGl2RWxlbWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnb2JqZWN0JylbMF07ICAgICAgICAgICAgICAgICAgICB2aXpFbGVtZW50LnN0eWxlLndpZHRoPScxMDAlJzt2aXpFbGVtZW50LnN0eWxlLmhlaWdodD0oZGl2RWxlbWVudC5vZmZzZXRXaWR0aCowLjc1KSsncHgnOyAgICAgICAgICAgICAgICAgICAgdmFyIHNjcmlwdEVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzY3JpcHQnKTsgICAgICAgICAgICAgICAgICAgIHNjcmlwdEVsZW1lbnQuc3JjID0gJ2h0dHBzOi8vcHVibGljLnRhYmxlYXUuY29tL2phdmFzY3JpcHRzL2FwaS92aXpfdjEuanMnOyAgICAgICAgICAgICAgICAgICAgdml6RWxlbWVudC5wYXJlbnROb2RlLmluc2VydEJlZm9yZShzY3JpcHRFbGVtZW50LCB2aXpFbGVtZW50KTsgICAgICAgICAgICAgICAgDQo8L3NjcmlwdD4NCjwvdGQ+DQo8L3RyPg0KPC90YWJsZT4gICAgICAgICAgICANClw=